﻿using UnityEngine;
using System.Collections;
using System.Reflection;
using System;

namespace PP.Basic
{
    /// <summary>
    /// 普通单例
    /// 无线程安全
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class SingletonUnsafe<T> where T : new()
    {
        protected static T _instance;
        public static T Instance => _instance ?? (_instance = new T());
    }

    /// <summary>
    /// 可释放的单例
    /// </summary>
    public abstract class SingletonDisposable<T> where T : IDisposable, new()
    {
        // Public Variables Begin
        protected static T _instance;
        public static T Instance => _instance ?? (_instance = new T());
        // Public Variables End

        // IDisposable Methods Begin
        private bool _isDisposed;

        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                OnDispose();

                // TODO: free unmanaged resources (unmanaged objects) and override finalizer
                // TODO: set large fields to null
                _isDisposed = true;
                _instance = default;
            }
        }

        protected virtual void OnDispose()
        {

        }

        // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
        // ~FirebaseMessagingWrapperAndroid()
        // {
        //     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
        //     Dispose(disposing: false);
        // }

        public void Dispose()
        {
            // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
        // IDisposable Methods End
    }


    /// <summary>
    /// 普通单例
    /// 线程安全
    /// </summary>
    public abstract class Singleton<T> where T : new()
    {
        protected static T _instance;
        static object _lock = new object();
        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lock)
                    {
                        if (_instance == null)
                            _instance = new T();
                    }
                }
                return _instance;
            }
        }
    }


    /// <summary>
    /// 安全的可释放的多线程安全单例
    /// </summary>
    public abstract class SingletonSafeAndDisposable<T> where T : new()
    {
        protected static T _instance;
        protected static object _lock = new object();
        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lock)
                    {
                        if (_instance == null)
                            _instance = new T();
                    }
                }
                return _instance;
            }
        }


        // IDisposable Methods Begin
        private volatile bool _isDisposed;

        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed)
                return;

            lock (_lock)
            {
                if (_isDisposed)
                    return;

                OnDispose();

                // TODO: free unmanaged resources (unmanaged objects) and override finalizer
                // TODO: set large fields to null
                _isDisposed = true;
                _instance = default;
            }
        }

        protected virtual void OnDispose()
        {

        }

        // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
        // ~FirebaseMessagingWrapperAndroid()
        // {
        //     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
        //     Dispose(disposing: false);
        // }

        public void Dispose()
        {
            // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
        // IDisposable Methods End
    }

    /// <summary>
    /// Unity场景中的单例
    /// 会随着场景的切换而销毁
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingleton<T> : MonoBehaviour where T : Component
    {
        protected bool _isInited = false;
        public bool IsInited => _isInited;

        protected static T _instance;
        public static T Instance => _instance;

        protected virtual void Awake()
        {
            // Already exists and not this, then destroy this gameobject and return.
            if (!ReferenceEquals(_instance, null) && !ReferenceEquals(_instance, this))
            {
                Debug.LogWarning($"This should not happen. {typeof(T).Name} should not be duplicated.");
                Destroy(gameObject);
                return;
            }
            _instance = this as T;

            Initiate();
        }

        /// <summary>
        /// 初始化组件，避免外部访问到未初始化的内容
        /// </summary>
        public virtual void Initiate()
        {
            if (_isInited)
                return;
            _isInited = true;

            OnInit();
        }

        protected virtual void OnInit()
        {
        }

        protected virtual void OnDestroy()
        {
            if (ReferenceEquals(_instance, this))
                _instance = null;
        }
    }

    /// <summary>
    /// Unity全局单例
    /// 不随着场景的切换而销毁
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingletonDontDestroyOnLoad<T> : UnitySingleton<T> where T : Component
    {
        protected override void Awake()
        {
            base.Awake();
            DontDestroyOnLoad(gameObject);
        }
    }

    /// <summary>
    /// Unity场景中查找到的单例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingletonFindOfType<T> : MonoBehaviour where T : Component
    {
        protected bool _isInited = false;
        public bool IsInited => _isInited;

        protected static T _instance;
        public static T Instance
        {
            get
            {
                if (ReferenceEquals(_instance, null))
                {
                    _instance = FindObjectOfType(typeof(T), true) as T;
                }
                return _instance;
            }
        }

        protected virtual void Awake()
        {
            // Already exists and not this, then destroy this GameObject and return.
            if (!ReferenceEquals(_instance, null) && !ReferenceEquals(_instance, this))
            {
                Debug.LogWarning($"This should not happen. {typeof(T).Name} should not be duplicated.");
                Destroy(this);
                return;
            }
            _instance = this as T;

            Initiate();
        }

        /// <summary>
        /// 初始化组件，避免外部访问到未初始化的内容
        /// </summary>
        public virtual void Initiate()
        {
            if (_isInited)
                return;
            _isInited = true;

            OnInit();
        }

        protected virtual void OnInit()
        {
        }

        protected virtual void OnDestroy()
        {
            if (ReferenceEquals(_instance, this))
                _instance = null;
        }
    }

    /// <summary>
    /// Unity场景中查找到的单例
    /// 带有Initiate()方法，用于初始化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingletonFindOfTypeWithInitiate<T> : MonoBehaviour where T : Component
    {
        protected bool _isInited = false;
        public bool IsInited => _isInited;

        protected static T _instance;
        public static T Instance
        {
            get
            {
                if (ReferenceEquals(_instance, null))
                {
                    _instance = FindObjectOfType(typeof(T), true) as T;
                    if (_instance != null)
                    {
                        // Call Initiate() method.
                        var instance = _instance as UnitySingletonFindOfTypeWithInitiate<T>;
                        instance?.Initiate();
                    }
                }
                return _instance;
            }
        }

        protected virtual void Awake()
        {
            // Already exists and not this, then destroy this GameObject and return.
            if (!ReferenceEquals(_instance, null) && !ReferenceEquals(_instance, this))
            {
                Debug.LogWarning($"This should not happen. {typeof(T).Name} should not be duplicated.");
                Destroy(this);
                return;
            }

            _instance = this as T;

            Initiate();
        }

        /// <summary>
        /// 初始化组件，避免外部访问到未初始化的内容
        /// </summary>
        public virtual void Initiate()
        {
            if (_isInited)
                return;
            _isInited = true;

            OnInit();
        }

        protected virtual void OnInit()
        {
        }

        protected virtual void OnDestroy()
        {
            if (ReferenceEquals(_instance, this))
                _instance = null;
        }
    }

    /// <summary>
    /// Unity场景中的单例，会随着场景的切换而销毁;
    /// 如果场景中存在，则初始化并使用；否则调用CreateSingletonObject方法或创建一个新的GameObject并添加组件；再使用。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingletonWithCreateMethod<T> : MonoBehaviour where T : Component
    {
        protected bool _isInited = false;
        public bool IsInited => _isInited;

        protected static T _instance;
        public static T Instance
        {
            get
            {
                if (ReferenceEquals(_instance, null))
                {
                    var type = typeof(T);
                    _instance = FindObjectOfType(type, true) as T;
                    if (_instance != null)
                    {
                        // Call Initiate() method.
                        var instance = _instance as UnitySingletonWithCreateMethod<T>;
                        instance?.Initiate();
                    }
                    else
                    {
                        _instance = CreateSingleton();
                    }
                }
                return _instance;
            }
        }

        /// <summary>
        /// 调用类型中的CreateSingletonObject方法，创建GameObject，再获取或添加组件
        /// 若没有CreateSingletonObject方法，则创建一个新的GameObject
        /// </summary>
        protected static T CreateSingleton()
        {
            GameObject go = null;
            var createMethod = typeof(T).GetMethod("CreateSingletonObject");
            if (createMethod != null)
            {
                // CreateSingletonObject() static method exists, then call it.
                go = createMethod.Invoke(null, null) as GameObject;
            }
            else
            {
                go = new GameObject($"~{typeof(T).Name}");
            }

            var co = go.GetComponent<T>();
            if (co == null)
            {
                co = go.AddComponent<T>();
            }

            // go.hideFlags = HideFlags.DontSave;
            // go.hideFlags = HideFlags.HideAndDontSave;
            // go.hideFlags = HideFlags.HideInHierarchy;

            return co;
        }

        protected virtual void Awake()
        {
            // Already exists and not this, then destroy this gameobject and return.
            if (!ReferenceEquals(_instance, null) && !ReferenceEquals(_instance, this))
            {
                Debug.LogWarning($"This should not happen. {typeof(T).Name} should not be duplicated.");
                Destroy(gameObject);
                return;
            }
            _instance = this as T;

            Initiate();
        }

        /// <summary>
        /// 初始化组件，避免外部访问到未初始化的内容
        /// </summary>
        public virtual void Initiate()
        {
            if (_isInited)
                return;
            _isInited = true;

            OnInit();
        }

        protected virtual void OnInit()
        {
        }

        protected virtual void OnDestroy()
        {
            if (ReferenceEquals(_instance, this))
                _instance = null;
        }
    }

    /// <summary>
    /// Unity全局单例，不随着场景的切换而销毁
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class UnitySingletonWithCreateMethodDontDestroyOnLoad<T> : UnitySingletonWithCreateMethod<T> where T : Component
    {
        protected override void Awake()
        {
            base.Awake();
            DontDestroyOnLoad(gameObject);
        }
    }
}